package com.tianji.learning.service.impl;

import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.tianji.common.utils.DateUtils;
import com.tianji.common.utils.UserContext;
import com.tianji.learning.constants.RedisConstants;
import com.tianji.learning.domain.po.PointsRecord;
import com.tianji.learning.domain.vo.PointsStatisticsVO;
import com.tianji.learning.enums.PointsRecordType;
import com.tianji.learning.mapper.PointsRecordMapper;
import com.tianji.learning.service.IPointsRecordService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.IntSummaryStatistics;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 * 学习积分记录，每个月底清零 服务实现类
 * </p>
 *
 * @author yangyu
 * @since 2023-07-29
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class PointsRecordServiceImpl extends ServiceImpl<PointsRecordMapper, PointsRecord> implements IPointsRecordService {

    private final PointsRecordMapper pointsRecordMapper;

    private final StringRedisTemplate redisTemplate;

    /**
     * 新增积分明细
     *
     * @param userId 用户id
     * @param points 积分值
     * @param type   积分方式
     */
    @Override
    public void addPointsRecord(Long userId, Integer points, PointsRecordType type) {
        log.info("新增积分明细: " + userId +"--"+ points +"--"+ type);
        LocalDateTime now = LocalDateTime.now();
        int maxPoints = type.getMaxPoints();    //获取上限值

        //1.判断积分方式，是否有上限值
        if (maxPoints > 0) {
            //2.有上限，则判断是否超过上限
            //2.1.获取今日开始时间和结束时间
            LocalDateTime startTime = DateUtils.getDayStartTime(now);
            LocalDateTime endTime = DateUtils.getDayEndTime(now);

            //2.2.获取用户今日当前类型的所有积分记录
            List<PointsRecord> records = list(Wrappers.<PointsRecord>lambdaQuery()
                    .eq(PointsRecord::getUserId, userId)
                    .eq(PointsRecord::getType, type)
                    .between(PointsRecord::getCreateTime, startTime, endTime));

            //2.3.统计用户今日已得积分
//            Integer sum = records.stream().collect(Collectors.summingInt(PointsRecord::getPoints));
            int sum = records.stream().mapToInt(PointsRecord::getPoints).sum();

            //2.4.判断是否超过今日上限
            if (sum >= maxPoints) {
                //2.5.超过，直接结束
                return;
            }
            //2.6.没超过，新增积分明细
            if (sum + points > maxPoints) { //防止超过上限
                points = maxPoints - sum;  //如果上限50，今日已得45，那么这次添加积分只能添加5分
            }
        }

        //3.没有上限，新增积分明细记录
        PointsRecord p = new PointsRecord();
        p.setPoints(points); //新的积分值
        p.setUserId(userId);
        p.setType(type);
        save(p);

        //4.更新用户总积分到Redis
        //拼接key,积分实时排行榜的Key的前缀：boards:202301
        String key = RedisConstants.POINTS_BOARD_KEY_PREFIX //boards:
                + now.format(DateUtils.POINTS_BOARD_SUFFIX_FORMATTER); //yyyyMM
        redisTemplate.opsForZSet().incrementScore(key,userId.toString(),points);
    }


    /**
     * 查询我的今日积分
     *
     * @return 每日积分统计实体
     */
    @Override
    public List<PointsStatisticsVO> queryMyPointsToday() {
        log.info("查询我的今日积分");
        //1.获取登录用户id
        Long userId = UserContext.getUser();

        //2.获取今日开始时间和结束时间
        LocalDateTime now = LocalDateTime.now();
        LocalDateTime startTime = DateUtils.getDayStartTime(now);
        LocalDateTime endTime = DateUtils.getDayEndTime(now);

        //3.查询我的今日积分
        List<PointsRecord> list = pointsRecordMapper.queryMyPointsToday(userId, startTime, endTime);

        //4.封装返回
        List<PointsStatisticsVO> vos = new ArrayList<>();
        for (PointsRecord pointsRecord : list) {
            PointsStatisticsVO vo = new PointsStatisticsVO();
            vo.setType(pointsRecord.getType().getDesc());   //积分类型描述
            vo.setMaxPoints(pointsRecord.getType().getValue()); //每日积分上限
            vo.setPoints(pointsRecord.getPoints()); //今日以获取积分
            vos.add(vo);
        }
        return vos;
    }
}
